#include "Dwarf.Unmanaged.Hybrid.h"

//Pointers to the factory functions.
static DLLParseArguments pDLLParseArguments;
static DLLUsage pDLLUsage;
static DLLStart pDLLStart;
static DLLStop pDLLStop;

//Pointers to dll.
static HINSTANCE hInstDll;

// Constructor that init strings.
Settings :: Settings()
{
	inputFile = new char[BUFFER_SIZE];
	resultFile = new char[BUFFER_SIZE];
	profileFile = new char[BUFFER_SIZE];

	inputFile[0] = resultFile[0] = profileFile[0] = '\0';

}

// Constructor that dispose strings.
Settings :: ~Settings()
{
	delete inputFile;
	delete resultFile;
	delete profileFile;
}

// Get one line from stream.
static void getNextLine(char* str, FILE* file) 
{
	short count = 0;
	char ch = ' ';    

	while (!feof(file) && (ch == ' ' || ch == '\n' || ch == '\r')) 
	{
		ch = (char)getc(file);
	}

	str[count] = ch;
	while (!feof(file) && ch != '\r' && ch != '\n' && ch != ' ') 
	{
		str[++count] = (ch = (char)getc(file));
	}

	str[count] = '\0';
}

// Parse input file into solver's structures.
int Settings::parseConfigFile(Solver* ugsolver) 
{
	FILE *file;

	// Open the file to read from.
	if( fopen_s(&file, inputFile, "rb")) 
	{
		printf("Can't open configfile!\r\n");
		(pDLLUsage)();

		return -1;
	}

	char *str = new char[BUFFER_SIZE];

	//Get epsilon.
	getNextLine(str, file);
	ugsolver->epsilon = atof(str);

	//Get power of graph.
	getNextLine(str, file);
	ugsolver->numVertex = atoi(str);

	//Get number of verteces.
	getNextLine(str, file);
	ugsolver->numTriangles = atoi(str);

	unsigned int i,j;

	//Init arrays.
	ugsolver->value = new double[ugsolver->numVertex];

	ugsolver->triangles[0] = new unsigned int[ugsolver->numTriangles];
	ugsolver->triangles[1] = new unsigned int[ugsolver->numTriangles];
	ugsolver->triangles[2] = new unsigned int[ugsolver->numTriangles];

	ugsolver->neighborhood = new unsigned int*[ugsolver->numVertex];

	ugsolver->numNeighbors = new unsigned int[ugsolver->numVertex];

	i = j = 0;

	//Get values of graph.
	while(!feof(file) && j < 1)
	{
		getNextLine(str, file);
		ugsolver->value[i] = atof(str);

		i ++;

		if (i >= ugsolver->numVertex) 
		{
			i = 0;
			j ++;
		}
	}    

	i = j = 0;

	//Get triangles.
	while(!feof(file) && j < 3)
	{
		getNextLine(str, file);
		ugsolver->triangles[j][i] = atoi(str);

		i ++;

		if (i >= ugsolver->numTriangles) 
		{
			i = 0;
			j ++;
		}
	} 

	delete str;

	//Dispose input file.
	fclose(file);

	return 0;
}

// Init variables, parse cli params and input file.
int Settings::init(int argc, char** argv, Solver *ugsolver) 
{

	// Load the dll into the address space
	//fix: C4706
	//if (!(hInstDll = LoadLibraryA("CliTools"))) 
    //{
	hInstDll = LoadLibraryA("CliTools");
	if(!hInstDll)
	{
		printf("Error while loading CliTools.dll.");
		return -1;
	}

	// Retrieve a pointer to the factory function
	pDLLParseArguments = 
		(DLLParseArguments) GetProcAddress(hInstDll, "parseArguments");

	pDLLUsage =
		(DLLUsage) GetProcAddress(hInstDll, "usage");

	pDLLStart = 
		(DLLStart) GetProcAddress(hInstDll, "start");

	pDLLStop = 
		(DLLStop) GetProcAddress(hInstDll, "stop");

	//Parse cli params.
	if ((pDLLParseArguments)(argc, argv, &inputFile, &profileFile, &resultFile)) 
	{
		FreeLibrary(hInstDll); 
		return -1;
	}

	//Parse input file.
	if (parseConfigFile(ugsolver)) 
	{
		FreeLibrary(hInstDll); 
		return -1;
	}

	//Write settings if it's needed.
	writeSettings(ugsolver);	
	return 0;
}

// Start the time count.
void Settings::start() 
{
	(pDLLStart)();
}

// Problem results output.
void Settings::finish(Solver *ugsolver)
{
	double time;
	(pDLLStop)(&time);

	//Release dll.
	FreeLibrary(hInstDll);//*/

	printf("\r\n");
	printf("Clock time (sec): %.8f \r\n", time);  

	FILE* outputResult = 0;
	FILE* outputProfile = 0;

	if( fopen_s(&outputProfile, profileFile , "wb")) 
	{
		printf("Can't create profile file!\r\n");            
		fclose(outputProfile);
		return;
	}

	if( fopen_s(&outputResult, resultFile , "wb")) 
	{
		printf("Can't create result file!\r\n");   
		fclose(outputResult);
		return;
	}

	fprintf(outputProfile, "#Dwarfname:%s\r\n",DWARF_NAME);

	char tmpbuf[BUFFER_SIZE];
	_tzset();

	_strdate_s( tmpbuf, BUFFER_SIZE );
	fprintf(outputProfile, "#Time: %s ",tmpbuf);

	_strtime_s( tmpbuf, BUFFER_SIZE );
	fprintf(outputProfile, "%s \r\n",tmpbuf);

	fprintf(outputProfile, "#Dimensions: 2\r\n");
	fprintf(outputProfile, "#Epsilon: %.8f \r\n", ugsolver->epsilon);
	fprintf(outputProfile, "#Vertex number: %d \r\n", ugsolver->numVertex);
	fprintf(outputProfile, "#Triangle number: %d \r\n", ugsolver->numTriangles);
	fprintf(outputProfile, "#Result time (sec): %.8f\r\n", time);
	fprintf(outputResult, "#Result vector:\r\n");

	for (unsigned int j = 0; j < ugsolver->numVertex; j ++) 
	{                
		fprintf(outputResult, "%0.8f ", ugsolver->resultValue[j]);
	}
	fprintf(outputResult, "\r\n");
	fprintf(outputProfile, "#eof");//*/

	fclose(outputProfile);
	fclose(outputResult);

}

// Write settings.
void Settings::writeSettings(Solver *ugsolver)
{
	// Write general settings.
	printf("Kernel settings summary : \r\n");
	printf("Dwarf name              : %s \r\n", DWARF_NAME);
	printf("Epsilon                 : %.8f \r\n", ugsolver->epsilon);
	printf("Vertex number           : %d \r\n", ugsolver->numVertex);
	printf("Triangle number         : %d \r\n", ugsolver->numTriangles);
	printf("Inputfile               : %s \r\n", inputFile);
	printf("Outputfile              : %s \r\n", resultFile);    
	printf("\r\n");

#ifdef DEBUG								// Debug log mode.
	
	printf("Initial domain:\r\n");
	printf("Value data:\r\n");
	// Write values of graph.
	for (unsigned int j = 0; j < ugsolver->numVertex; j ++) 
	{                
		printf("%0.8f ", ugsolver->value[j]);
	}
	printf("\r\n");

	printf("Triangles:\r\n");
	// Write verteces of triangles.
	for (int i = 0; i < 3; i ++) 
	{
		for (unsigned int j = 0; j < ugsolver->numTriangles; j ++) 
		{                
			printf("%d ", ugsolver->triangles[i][j]);
		}
		printf("\r\n");
	}    
	printf("\r\n");

#endif DEBUG
}